package org.simpleframework.util;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executors;


/**
 * @author
 * @date 2022/10/4 15:32
 **/
@Slf4j
public class ClassUtil {


    /**
     * @param field        成员变量字段
     * @param targetObject 目标对象
     * @param value        需要注入的值
     * @param accessible   是否公开
     */
    public static void setField(Field field, Object targetObject, Object value, boolean accessible) {
        field.setAccessible(accessible);
        try {
            field.set(targetObject,value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据反射构造获取实例对象
     *
     * @param clazz
     * @return
     */
    public static Object getInstance(Class<?> clazz, Boolean accessible) {
        try {
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(accessible);
            Object instance = constructor.newInstance();

            return instance;
        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }


    /**
     * 根据包名递归获取对应的class文件
     *
     * @param packageName
     * @return
     */
    public static Set<Class<?>> extractPackageClass(String packageName) {
        if (ValidationUtil.isEmpty(packageName)) {
            throw new RuntimeException("packName Not Null");
        }
        ClassLoader classLoader = getClassLoader();
        Set<Class<?>> hashSet = new HashSet<>();
        URL url = classLoader.getResource(packageName.replace(".", "/"));
        if (url.getProtocol().equals("file")) { // 如果协议是file的话
            // 就进行递归查找所有的class文件
            File directFile = new File(url.getPath());
            etractFileClass(directFile, packageName, hashSet); // 递归查找所有的class文件
        }
        return hashSet;

    }


    /**
     * 递归查找所有的class文件
     *
     * @param directFile  递推的条件
     * @param packageName 包名
     * @param classSet    容器用于递归收集 class文件
     */
    private static void etractFileClass(File directFile, String packageName, Set<Class<?>> classSet) {
        if (!directFile.isDirectory()) { // 递归终止条件
            return;
        }
        File[] files = directFile.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                if (file.isDirectory()) { // 如果是目录的话就直接返回
                    return true;
                } else { // 如果不是目录的话
                    if (file.getName().endsWith(".class")) { //如果是class文件的话
                        // 根据名字获取对应的class
                        Class<?> clazz = getClassNameByAbsolatePath(file.getPath(), packageName);
                        // 将class 文件添加到set集合中
                        classSet.add(clazz);
                    }
                }
                return false;
            }

            /***
             *
             * @param path 入参  F:\javaProject\simpleSpringPR\target\classes\com\it\Test.class
             * @param packageName 包名 用来截取
             * @return 根据绝对路径获取到的class对象
             */
            private Class<?> getClassNameByAbsolatePath(String path, String packageName) {
                path = path.replace("\\", ".");
                int i = path.indexOf(packageName);
                // 获得全限定类名

                String className = path.substring(i, path.lastIndexOf(".class"));
                Class<?> clazz = getClassByClassName(className);
                return clazz;
            }
        });
        if (files != null) {  // 防止foreach 循环的时候空指针 异常
            for (File file : files) {
                etractFileClass(file, packageName, classSet); // 递归遍历
            }

        }
    }


    /**
     * @param className 入参 com.it.Test
     * @return 对应的class对象
     */
    private static Class<?> getClassByClassName(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            return clazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException(" 出错");
        }
    }

    /**
     * 获取类加载器
     */
    private static ClassLoader getClassLoader() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        return classLoader;
    }


    public static void main(String[] args) {
        ClassUtil classUtil = new ClassUtil();
        Set<?> objects = classUtil.extractPackageClass("com.it");

    }
}
